package net.entelijan.cobean.combobox;

import java.awt.Component;
import java.util.List;

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

import net.entelijan.cobean.core.ColumnDesc;
import net.entelijan.cobean.core.IInitializer;
import net.entelijan.cobean.core.ISingleSelectionListCobean;
import net.entelijan.cobean.core.impl.AbstractComponentBean;
import net.entelijan.cobean.util.CobeanUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DefaultComboBoxInitializer<T> implements
		IInitializer<ISingleSelectionListCobean<T>> {

	private static Log log = LogFactory
			.getLog(DefaultComboBoxInitializer.class);

	private List<T> items;

	private List<ColumnDesc> columnDescs;

	private JComboBox coComboBox;

	private T selectedItem;

	public DefaultComboBoxInitializer() {
		super();
	}

	@Override
	public ISingleSelectionListCobean<T> initialize() {
		InternalComponentBean re = new InternalComponentBean();
		coComboBox.setModel(new InternalComboboxModel(re));
		coComboBox.setRenderer(new InternalCellRenderer());
		return re;
	}

	private final class InternalCellRenderer extends BasicComboBoxRenderer {
		private static final long serialVersionUID = 1L;

		@Override
		public Component getListCellRendererComponent(JList list, Object model,
				int index, boolean isSelected, boolean cellHasFocus) {
			JLabel re = (JLabel) super.getListCellRendererComponent(list,
					model, index, isSelected, cellHasFocus);
			String text = CobeanUtil.createText(model, columnDescs);
			re.setText(text);
			return re;
		}
	}

	private class InternalComponentBean extends AbstractComponentBean implements
			ISingleSelectionListCobean<T> {

		public InternalComponentBean() {
			super();
		}

		@Override
		public List<T> getValue() {
			return items;
		}

		@Override
		public T getSelectedValue() {
			return selectedItem;
		}

		@Override
		public void setValue(List<T> value) {
			List<T> oldValue = items;
			items = value;
			selectedItem = null;
			log.debug("[setData] " + oldValue + "->" + value);
			propertyChangeSupport.firePropertyChange("value", oldValue, value);
			coComboBox.setModel(new InternalComboboxModel(this));
			coComboBox.repaint();
		}

		@Override
		public void setSelectedValue(T selData) {
			T oldSelData = selectedItem;
			selectedItem = selData;
			log.debug("[setSelectedValue] " + oldSelData + "->" + selData);
			propertyChangeSupport.firePropertyChange("selectedValue",
					oldSelData, selData);
			coComboBox.repaint();
		}
		
		@Override
		public String toString() {
			return "Cobean[JComboBox] ";
		}

	}

	private class InternalComboboxModel extends AbstractListModel implements
			ComboBoxModel {

		private InternalComponentBean cobean;

		private static final long serialVersionUID = 1L;

		public InternalComboboxModel(InternalComponentBean cobean) {
			super();
			this.cobean = cobean;
		}

		@Override
		public Object getSelectedItem() {
			return selectedItem;
		}

		@SuppressWarnings("unchecked")
		@Override
		public void setSelectedItem(Object anItem) {
			cobean.setSelectedValue((T) anItem);
		}

		@Override
		public Object getElementAt(int index) {
			Object re = null;
			if (items != null) {
				re = items.get(index);
			}
			return re;
		}

		@Override
		public int getSize() {
			return items == null ? 0 : items.size();
		}

	}

	public List<ColumnDesc> getColumnDescs() {
		return columnDescs;
	}

	public void setColumnDescs(List<ColumnDesc> columnDescs) {
		this.columnDescs = columnDescs;
	}

	public JComboBox getCoComboBox() {
		return coComboBox;
	}

	public void setCoComboBox(JComboBox comp) {
		this.coComboBox = comp;
	}

}
